#ifndef TROYGLCONTROLLER_H
#define TROYGLCONTROLLER_H

#include <QDebug>
#include <cmath>

#include "robotglcontroller.h"
#include "robotcommands.h"
#include "troyglview.h"
#include "troy.h"
#include "history.h"

/**
 * @brief The controller for Troy associated with a TroyGLView.
 * Inherits RobotGLController.
 *
 * The TroyGLController is responsible for manipulating our Troy model
 * when the user interacts with the openGL wireframe display.  For
 * example, when a user drags the arms, the model is updated and the
 * view refreshed to show the dragging.
*/
class TroyGLController : public RobotGLController
{
    Q_OBJECT

public:
    explicit TroyGLController(QObject* parent = 0);

    void loadModel(Robot *robot);

    //Implemented virtual functions from the parent class
    void mousePressEvent(QMouseEvent* event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

    //Performs inverse kinematics to position the end point of the segment
    //as close as possible to the goal in 3D space by manipulating the
    //specified joints.
    //Returns the number of calculations needed.
    int inverseKinematics(const NameGroup segmentNames, QVector3D goal, QList<int> jointIDs);

protected:
    //Creates the GUIComponents for Troy.  It is called after
    //the Troy model is loaded.
    void initComponents();

    virtual void componentPicked(NameGroup names);
    virtual void noPick();

private:
    RobotCommand* _recentCommand;
    //We need a single command for the history to undo a dragging action,
    //not a bunch of commands that undo a small movement
    RobotCommandGroup* _dragCommand;
    NameGroup _currentSelection;

    //Variables to help with mouse dragging and editing the robot via drag
    double _prevX, _prevY, _prevZ;
    bool _mouseDrag, _changeOccured;

    //Helper function for inverse kinematics.  Returns the amount of change
    //to the joint that needs to be made in order to move closer to the goal
    double calcGradient(const RobotSegment* segment, QVector3D goal, int jointID);

private slots:
    //Listening to the robot helps the controller know when a change has occured
    void onRobotChanged();
};

#endif // TROYGLCONTROLLER_H
